/**
 * This file is Copyright © 2008 Software Craftsmen Limited. All Rights Reserved.
 */
package com.softwarecraftsmen.orogeny.buildEnvironments;

import com.softwarecraftsmen.orogeny.BuildScript.BuildSyntaxException;
import com.softwarecraftsmen.orogeny.execution.AllProperties;
import com.softwarecraftsmen.orogeny.filing.AbsoluteDirectory;
import static com.softwarecraftsmen.orogeny.filing.AbsoluteDirectory.CurrentUserHomeDirectory;
import static com.softwarecraftsmen.orogeny.filing.AbsoluteDirectory.CurrentWorkingDirectory;
import com.softwarecraftsmen.orogeny.filing.AbsolutePaths;
import static com.softwarecraftsmen.orogeny.filing.fileSystems.AbstractFileSystem.CurrentFileSystem;
import com.softwarecraftsmen.orogeny.filing.fileSystems.FileSystem;
import com.softwarecraftsmen.orogeny.operatingSystems.OperatingSystem;
import com.softwarecraftsmen.orogeny.operatingSystems.OperatingSystemFamily;
import com.softwarecraftsmen.orogeny.operatingSystems.OperatingSystemPlatform;
import com.softwarecraftsmen.orogeny.properties.Evaluatable;
import com.softwarecraftsmen.orogeny.properties.PropertyName;
import org.jetbrains.annotations.NotNull;

import static java.lang.String.format;
import java.util.*;
import static java.util.Locale.UK;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ConcreteBuildEnvironment implements BuildEnvironment
{
	private final String currentBuildName;
	private final UUID currentBuildUUid;
	private final BuildDateTime currentBuildDateTime;
	private final AbsoluteDirectory currentBuildDirectory;
	private final AllProperties allProperties;
	private final Map<String, AbsolutePaths> registeredPaths;
	private final Lock registeredPathsReadLock;
	private final Lock registeredPathsWriteLock;

	public ConcreteBuildEnvironment(final @NotNull String currentBuildName, final @NotNull UUID currentBuildUUid, final @NotNull BuildDateTime currentBuildDateTime, final @NotNull AbsoluteDirectory currentBuildDirectory, final @NotNull AllProperties allProperties)
	{
		this.currentBuildName = currentBuildName;
		this.currentBuildUUid = currentBuildUUid;
		this.currentBuildDateTime = currentBuildDateTime;
		this.currentBuildDirectory = currentBuildDirectory;
		this.allProperties = allProperties;
		this.registeredPaths = new LinkedHashMap<>();
		final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(false);
		registeredPathsReadLock = readWriteLock.readLock();
		registeredPathsWriteLock = readWriteLock.writeLock();
	}

	@NotNull
	public String currentBuildName()
	{
		return currentBuildName;
	}

	@NotNull
	public UUID currentBuildUuid()
	{
		return currentBuildUUid;
	}

	@NotNull
	public BuildDateTime currentBuildDateTime()
	{
		return currentBuildDateTime;
	}

	@NotNull
	public OperatingSystem currentOperatingSystem()
	{
		return OperatingSystem.currentOperatingSystem();
	}

	@NotNull
	public OperatingSystemPlatform currentOperatingSystemPlatform()
	{
		return OperatingSystemPlatform.currentOperatingSystemPlatform();
	}

	@NotNull
	public OperatingSystemFamily currentOperatingSystemFamily()
	{
		return OperatingSystemFamily.currentOperatingSystemFamily();
	}

	@NotNull
	public FileSystem currentFileSystem()
	{
		return CurrentFileSystem;
	}

	@NotNull
	public AbsoluteDirectory currentWorkingDirectory()
	{
		return CurrentWorkingDirectory;
	}

	@NotNull
	public AbsoluteDirectory currentUserHomeDirectory()
	{
		return CurrentUserHomeDirectory;
	}

	@NotNull
	public AbsoluteDirectory currentBuildDirectory()
	{
		return currentBuildDirectory;
	}

	@NotNull
	public AbsolutePaths registeredPaths(final @NotNull String name) throws RegisteredClassPathUnavailableException
	{
		registeredPathsReadLock.lock();
		try
		{
			if (!registeredPaths.containsKey(name))
			{
				throw new RegisteredClassPathUnavailableException(name);
			}
			return registeredPaths.get(name);
		}
		finally
		{
			registeredPathsReadLock.unlock();
		}
	}

	public void registerPaths(final @NotNull String name, final @NotNull AbsolutePaths classPath)
	{
		registeredPathsWriteLock.lock();
		try
		{
			if (registeredPaths.containsKey(name))
			{
				throw new BuildSyntaxException(format(UK, "The class path '%1$s' is already registered as '%2$s'", classPath, name));
			}
			registeredPaths.put(name, classPath);
		}
		finally
		{
			registeredPathsWriteLock.unlock();
		}
	}

	@NotNull
	public Evaluatable getProperty(final @NotNull PropertyName propertyName)
	{
		return allProperties.get(propertyName);
	}

	public void putProperty(final @NotNull PropertyName propertyName, final @NotNull Evaluatable evaluatable)
	{
		allProperties.put(propertyName, evaluatable);
	}

	@NotNull
	public SortedSet<PropertyName> allPropertyNames()
	{
		return new TreeSet<>(allProperties.keySet());
	}

	@NotNull
	public String toString()
	{
		return "ConcreteBuildEnvironment";
	}
}
